#include <iostream>
#include <memory>
#include <unordered_map>
#include "Epoller.hpp"
#include "Connection.hpp"
#include "Common.hpp"
const int evsize = 128;
class Reactor
{
public:
    Reactor()
        : _epoller_ptr(make_unique<Epoller>()), _isrunning(false)
    {
    }
    void Start()
    {
        _isrunning = true;
        if (_connections.empty())
        {
            LOG(Level::ERROR) << "_connections empty";
            return;
        }
        while (_isrunning)
        {
            int time = 500;
            int n = _epoller_ptr->EpollWait(_revs, evsize, time);
            if (n > 0)
            {
                for (int i = 0; i < n; i++)
                {
                    int fd = _revs->data.fd;
                    uint32_t event = _revs[i].events;
                    if (event & EPOLLERR)
                        event |= (EPOLLIN | EPOLLOUT);
                    if (event & EPOLLIN)
                    {
                        _connections[fd]->Recver();
                    }
                    if (event & EPOLLOUT)
                    {
                        _connections[fd]->Sender();
                    }
                }
            }
        }
    }
    void stop()
    {
        _isrunning = false;
    }
    bool isExistConnect(int fd)
    {
        auto ret = _connections.find(fd);
        if (ret == _connections.end())
            return false;
        return true;
    }
    void AddConnection(shared_ptr<Connection> conn)
    {
        if (isExistConnect(conn->GetFd()))
        {
            LOG(Level::WARING) << conn->GetFd() << " exist";
            return;
        }
        int fd = conn->GetFd();
        _connections[fd] = conn;
        conn->SetOwner(this);
        _epoller_ptr->EpollCtlAdd(fd, conn->GetEvents());
    }
    void DelConnection(int fd)
    {
        _epoller_ptr->EpollCtlDel(fd);
        _connections.erase(fd);
        close(fd);
        LOG(Level::INFO) << "client " << fd << " out...";
    }
    void EnableReadWrite(int fd, bool enableRead, bool enableWrite)
    {
        if (!isExistConnect(fd))
        {
            LOG(Level::WARING) << fd << " no exist";
            return;
        }
        uint32_t events = EPOLLET | (enableRead ? EPOLLIN : 0 | enableWrite ? EPOLLOUT : 0);
        _connections[fd]->SetEvents(events);
        _epoller_ptr->EpollCtlMod(fd, events);
    }
    ~Reactor()
    {
    }

private:
    // epoll模型
    unique_ptr<Epoller> _epoller_ptr;
    // 是否启动
    bool _isrunning;
    // 管理fd
    unordered_map<int, shared_ptr<Connection>> _connections;
    // 储存就绪文件
    epoll_event _revs[evsize];
};